import away3d.containers.*;
import away3d.materials.*;
import away3d.primitives.*;
import away3d.sprites.*;

import com.powerfl.frm.taf.*;

import flash.display.*;
import flash.filters.*;
import flash.utils.*;

internal var _trees:Object;
internal var _treeTag:Object;
internal var _treeCount:uint;
internal var _treeEvent:Dictionary;
internal var _treeFilter:Dictionary;

private function treeInit():void{
	_treeEvent = new Dictionary( true );
	_treeFilter = new Dictionary( true );
	_treeTag = {};
	_treeCount = 0;
	_trees = {'@ROOT':poolPullTree().init( '', '@ROOT', 'root', null )}; 
	addTree( '@ROOT', '@@STAGE', 'STAGE', STAGE, null );
	addTree( '@ROOT', '@@DATA', 'data', {}, null );
	addTree( '@DATA', '@@TEMPLATE', 'data', {}, null );
	addTree( '@DATA', '@@STATE', 'data', {}, null );
	addTree( '@DATA', '@@STATEVAR', 'data', {}, null );
	addTree( '@DATA', '@@local', 'data', {}, null );
	addTree( '@DATA', '@@global', 'data', {}, null );
	addTree( '@DATA', '@@script', 'data', {}, null );
	addTree( '@DATA', '@@eachs', 'data', {}, null );
	addTree( '@DATA', '@@param', 'data', {}, null );
	addTree( '@DATA', '@@treevar', 'data', {}, null );
}

final public function uniqueKey():String{
	++SELF._treeCount;
	return 'TREE_' + SELF._treeCount.toString();
}
final public function treeGet( $value:String ):*{
	var temp:Array, result:*, i:int, j:int;
	if( $value.indexOf( '.' ) < 0 ){
		result = SELF._trees[$value];
	}else{
		temp = $value.split( '.' );
		result = tdata( temp[0] );
		for( i = 1, j = temp.length ; i < j ; ++i ){
			result = result[temp[i]];
		}
	}
	return result;
}
final public function treeCheck( $key:String ):String{
	if( $key.charAt( 0 ) === '@' ){
		$key = $key.substr( 1 );
		if( SELF._trees[$key] ){
			return '';
		}
	}
	return $key;
}
final internal function addTree( $parent:String, $key:String, $type:String, $data:*, $param:TAFparam ):void{
	var parent:TAFtree, parentData:*, key:*;
	if( $key === '' ){
		++SELF._treeCount;
		$key = 'AUTOKEY_' + SELF._treeCount.toString();
	}else{
		$key = treeCheck( $key );
	}
	
	if( $key === '' ){
		return;
	}else if( SELF._trees[$key] ){
		error( '이미 자식키가 존재합니다. - ' + $key +":"+SELF._trees[$key]);
	}
	
	//트리생성
	parent = SELF._trees[$parent];
	if( parent ){
		if( parent.children[$key] ){
			error( '부모에 이미 등록된 자식입니다.- ' + $parent + ' > ' + $key );
		}else{
			SELF._trees[$key] = poolPullTree().init( $parent, $key, $type, $data );
			parent.children[$key] = SELF._trees[$key]; 
		}
	}else{
		error( '부모키가 존재하지 않습니다. - ' + $parent );
	}
	//타입별 구상층 처리
	parentData = tdata( $parent );
	switch( $type ){
	case'stage':
		$data.name = $key;
		parentData.addChild( $data );
		if( $data.blendMode === 'normal' ){ 
			flowAdd_( $key + '@render', $data['render'] );
		}
		break;
	case'bitmapChild':
		$data.name = $key;
		parentData.addChild( $data );
		break;
	case'awayChild':
		$data.name = $key;
		if( parentData is View3D ){
			parentData.scene.addChild( $data );
		}else{
			parentData.addChild( $data );
		}
		break;
	case'awaySprite':
		if( parentData is View3D ){
			parentData.scene.addSprite( $data );
		}else{
			parentData.addSprite( $data );
		}
		break;
	case'awayLight':
		if( parentData is View3D ){
			parentData.scene.addLight( $data );
		}else{
			parentData.addLight( $data );
		}
		break;
	case'image':
		
		break;
	}
	//태그처리
	if( $param ){
		addTags_( $key, $param.tag );
		$param.applyBind( $key );
	}
}
final public function treeInRemove( ...$parent ):void{
	$parent = arrayStrip( $parent );
	orderAdd( null, function():void{
		treeInRemove_( $parent );
	} );
}
private function treeInRemove_( $parent:Array ):void{
	var child:*, parent:*;
	for each( parent in $parent ){
		for( child in objectClone( SELF._trees[parent].children ) ){
			treeRemove_( child );
		}
	}
}
final public function treeRemove( ...$children ):void{
	$children = arrayStrip( $children );
	orderAdd( null, function():void{
		var key:*;
		for each( key in $children ){
			treeRemove_( key );
		}
	} );
}
private function treeRemove_( $children:* ):void{
	var children:Array, key:*;
	if( $children is Array ){
		if( $children.length > 1 ){
			children = [];
			for each( key in $children ){
				if( key.charAt(0) === '@' ){
					children = children.concat( tagGet( key.substr( 1 ) ) );
				}else{
					children[children.length] = key;
				}
			}
			for each( key in children ){
				treeRemoveEach( key );
			}
		}else{
			$children = $children[0];
		}
	}else{
		if( $children is String ){}else{
			$children = $children.toString();
		}
		if( $children.charAt(0) === '@' ){
			children = tagGet( $children.substr( 1 ) )
			for each( key in children ){
				treeRemoveEach( key );
			}
		}else{
			treeRemoveEach( $children );
		}
	}
}
private function treeRemoveEach( $child:String ):void{
	var parent:TAFtree, child:TAFtree, childData:*, parentData:*, temp:Array, material:*;	
	child = treeGet( $child );
	if( child ){}else{
		return;
	}
	childData = child.data;
	parent = treeGet( child.parent );
	parentData = parent.data;
	treeInRemove_( [$child] );
	parent.children[$child] = null;
	if( SELF._treeEvent[childData] ){
		SELF._treeEvent[childData][0].apply( null, SELF._treeEvent[childData][1] );
		SELF._treeEvent[childData] = null;
	}
	if( SELF._treeFilter[childData] ){
		childData.filters = null;
		collectFilter( SELF._treeFilter[childData] );
		SELF._treeFilter[childData] = null;
	}
	if( tdata( '@treevar' )[child] ){
		tdata( '@treevar' )[child] = null;
	}
	tagTreeRemove_( $child );
	
	switch( child.type ){
	case'stage':
		parentData.removeChild( childData );
		temp = [];
		if( SELF._trees[$child+'@scene'] ){
			temp[temp.length] = $child+'@scene'; 
		}
		if( SELF._trees[$child+'@camera'] ){
			temp[temp.length] = $child+'@camera';
			 
		}
		if( SELF._trees[$child+'@target'] ){
			temp[temp.length] = $child+'@target';
		}
		if( temp.length ){
			treeRemove_( temp );
		}
		unbindRunner( [$child+'@render'], null );
		flowRemove( $child+'@render' );
		if( childData['down'] ){
			unbindRunner( [$child + '@down'], SELF._mouseDown );
			unbindRunner( [$child + '@up'], SELF._mouseUp );
			flowRemove( $child + '@down', $child + '@up' );
		}
		break;
	case'bitmapChild':
		parentData.removeChild( childData );
		break;
	case'awayChild':
		unbindMouse( [$child], '' );
		switch( parent.type ){
		case'stage':
			parentData.scene.removeChild( childData );
			break;
		case'awayChild':
			parentData.removeChild( childData );
			break;
		}
		if( childData is ObjectContainer3D ){}else{
			collectMaterial( childData.material );
		}
		collectAwayChild( childData );
		break;
	case'awaySprite':
		switch( parent.type ){
		case'stage':
			parentData.scene.removeSprite( childData );
			break;
		case'awayChild':
			parentData.removeSprite( childData );
			break;
		}
		collectMaterial( childData.material );
		poolCollectSprite3D( childData );
		break;
	case'awayLight':
		switch( parent.type ){
		case'stage':
			parentData.scene.removeLight( childData );
			break;
		case'awayChild':
			parentData.removeLight( childData );
			break;
		}
		break;
	case'data':
		break;
	case'image':
		if( childData ){
			childData.dispose();
		}
		treeRemove_( $child + '@size' );
		break;
	case'sound':
		poolCollectSound( childData );
		break;
	case'byte':
		childData.length = 0;
		break;
	case'ini':
		break;
	}
	poolCollectTree( SELF._trees[$child] );
	delete SELF._trees[$child];
}